package com.junxonline.instant.admin.service.config.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.junxonline.instant.dao.entity.dto.ui.TreeSelectNodeDTO;
import com.junxonline.instant.dao.entity.model.config.Organization;
import com.junxonline.instant.dao.entity.vo.config.OrganizationVO;
import com.junxonline.instant.dao.mapper.config.OrganizationMapper;
import com.junxonline.instant.admin.service.config.OrganizationService;
import com.junxonline.instant.common.annotation.DataScope;
import com.junxonline.instant.common.entity.common.CommonRespPage;
import com.junxonline.instant.common.enumeration.AdminErrorEnum;
import com.junxonline.instant.common.exception.AdminBizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 组织机构管理接口实现类
 *
 * @author JunX
 * @date 2021-06-30
 */
@Service
@Transactional
public class OrganizationServiceImpl extends ServiceImpl<OrganizationMapper, Organization> implements OrganizationService {

    @Autowired
    private OrganizationMapper organizationMapper;

    /**
     * 查询组织机构树（TreeSelect）
     *
     * @param wrapper 条件查询器
     * @return List<TreeSelectNodeDTO>
     */
    @Override
    @DataScope(isSelfSkip = true)
    public List<TreeSelectNodeDTO> queryOrganizationTree(QueryWrapper<Organization> wrapper) {
        wrapper.ne("t.type", 2);
        List<Organization> organizations = organizationMapper.queryList(wrapper);
        return this.getTreeSelectTree(organizations);
    }

    /**
     * 查询上级组织机构树（TreeSelect）
     *
     * @param vo      请求对象
     * @param wrapper 条件查询器
     * @return List<TreeSelectNodeDTO>
     */
    @Override
    @DataScope
    public List<TreeSelectNodeDTO> queryParentTree(OrganizationVO vo, QueryWrapper<Organization> wrapper) {
        if (vo.getType() != null && vo.getType() == 1) {
            wrapper.in("t.type", 0, 1);
        }
        else if (vo.getType() != null && vo.getType() == 2) {
            wrapper.eq("t.type", 1);
        }
        List<Organization> organizations = organizationMapper.queryList(wrapper);
        return this.getTreeSelectTree(organizations);
    }

    /**
     * 查询组织机构列表
     *
     * @param vo      请求对象
     * @param wrapper 条件查询器
     * @return CommonRespPage<Organization>
     */
    @Override
    @DataScope
    public CommonRespPage<Organization> queryList(OrganizationVO vo, QueryWrapper<Organization> wrapper) {
        // 条件查询
        wrapper.eq(vo.getType() != null, "t.type", vo.getType());
        wrapper.like(StrUtil.isNotBlank(vo.getName()), "t.name", vo.getName());
        wrapper.like(StrUtil.isNotBlank(vo.getLeader()), "t.leader", vo.getLeader());
        wrapper.eq(vo.getStatus() != null, "t.status", vo.getStatus());
        List<Organization> organizations = organizationMapper.queryList(wrapper);
        Page<Organization> page = new Page<>();
        page.setRecords(this.getOrganizationTree(organizations));
        page.setTotal(organizations.size());
        return CommonRespPage.success(page, this.getParentOrganizationTreeId(organizations));
    }

    /**
     * 查询组织机构
     *
     * @param id ID
     * @return Organization
     */
    @Override
    public Organization query(Long id) {
        Organization organization = organizationMapper.selectById(id);
        Assert.notNull(organization, AdminErrorEnum.DATA_IS_NOT_EXISTS.getMsg());
        return organization;
    }

    /**
     * 新增组织机构
     *
     * @param organization 请求参数
     */
    @Override
    public void add(Organization organization) {
        Integer count = organizationMapper.selectCount(new LambdaQueryWrapper<Organization>()
                .eq(Organization::getName, organization.getName()));
        if (count > 0) {
            throw new AdminBizException(AdminErrorEnum.DATA_IS_EXISTS);
        }
        organizationMapper.insert(organization);
        Organization model = organizationMapper.selectById(organization);
        model.setOrganizationId(organization.getId());
        organizationMapper.updateById(model);
    }

    /**
     * 编辑组织机构
     *
     * @param organization 请求参数
     */
    @Override
    public void edit(Organization organization) {
        Integer count = organizationMapper.selectCount(new LambdaQueryWrapper<Organization>()
                .ne(Organization::getId, organization.getId())
                .eq(Organization::getName, organization.getName()));
        if (count > 0) {
            throw new AdminBizException(AdminErrorEnum.DATA_IS_EXISTS);
        }
        organizationMapper.updateById(organization);
    }

    /**
     * 删除组织机构
     *
     * @param ids 请求参数
     */
    @Override
    public void delete(List<Long> ids) {
        organizationMapper.deleteBatchIds(ids);
        for (Long organizationId : ids) {
            organizationMapper.delete(new LambdaUpdateWrapper<Organization>().eq(Organization::getParentId, organizationId));
        }
    }

    /**
     * 查询机构的所有子机构ID
     *
     * @param organizationId 机构ID
     * @return Set<Long>
     */
    @Override
    public Set<Long> queryChildren(Long organizationId) {
        Set<Long> organizationIds = new HashSet<>();
        organizationIds.add(organizationId);
        List<Organization> childrenOrganizations = organizationMapper.queryChildren(organizationId);
        // 解析树形数据为平级结构
        treeToFlat(organizationIds, childrenOrganizations);
        return organizationIds;
    }

    /**
     * 树形结构转为扁平结构
     *
     * @param organizationIds 扁平集合
     * @param organizations   树形集合
     */
    private void treeToFlat(Set<Long> organizationIds, List<Organization> organizations) {
        for (Organization organization : organizations) {
            organizationIds.add(organization.getId());
            if (organization.getChildren() != null && organization.getChildren().size() > 0) {
                this.treeToFlat(organizationIds, organization.getChildren());
            }
        }
    }

    /**
     * 递归生成TreeSelect树
     *
     * @param organizations 机构集合
     * @return List<TreeSelectNodeDTO>
     */
    private List<TreeSelectNodeDTO> getTreeSelectTree(List<Organization> organizations) {
        List<TreeSelectNodeDTO> treeSelectNodeList = new ArrayList<>();
        for (TreeSelectNodeDTO node : getParentTreeSelectNode(organizations)) {
            this.getChildrenTreeSelectNode(node, organizations);
            treeSelectNodeList.add(node);
        }
        return treeSelectNodeList;
    }

    /**
     * 生成父级TreeSelect树
     *
     * @param organizations 机构集合
     * @return List<TreeSelectNodeDTO>
     */
    private List<TreeSelectNodeDTO> getParentTreeSelectNode(List<Organization> organizations) {
        List<TreeSelectNodeDTO> parentNodes = new ArrayList<>();
        Map<String, String> scopedSlots = new HashMap<>();
        scopedSlots.put("title", "title");
        for (Organization organization : organizations) {
            List<Organization> currentOrganizationParents = organizations.stream().filter(o -> o.getId().equals(organization.getParentId())).collect(Collectors.toList());
            if (currentOrganizationParents.size() <= 0) {
                parentNodes.add(new TreeSelectNodeDTO(organization.getId(), organization.getId(), null, organization.getName(), organization.getType(), scopedSlots));
            }
        }
        return parentNodes;
    }

    /**
     * 递归生成子TreeSelect树节点
     *
     * @param parentNode    上级节点
     * @param organizations 机构集合
     * @return TreeSelectNodeDTO
     */
    private TreeSelectNodeDTO getChildrenTreeSelectNode(TreeSelectNodeDTO parentNode, List<Organization> organizations) {
        List<TreeSelectNodeDTO> childrenTreeSelectNodes = new ArrayList<>();
        Map<String, String> scopedSlots = new HashMap<>();
        scopedSlots.put("title", "title");
        for (Organization organization : organizations) {
            if (parentNode.getKey().equals(organization.getParentId())) {
                childrenTreeSelectNodes.add(getChildrenTreeSelectNode(new TreeSelectNodeDTO(organization.getId(), organization.getId(), null, organization.getName(), organization.getType(), scopedSlots), organizations));
            }
        }
        if (childrenTreeSelectNodes.size() > 0) {
            parentNode.setChildren(childrenTreeSelectNodes);
        }
        return parentNode;
    }

    /**
     * 生成父级菜单树ID集合
     *
     * @param organizations 机构集合
     * @return List<String>
     */
    private List<String> getParentOrganizationTreeId(List<Organization> organizations) {
        List<String> parentOrganizationIds = new ArrayList<>();
        for (Organization organization : organizations) {
            List<Organization> currentOrganizationParents = organizations.stream().filter(o -> o.getId().equals(organization.getParentId())).collect(Collectors.toList());
            if (currentOrganizationParents.size() <= 0) {
                parentOrganizationIds.add(organization.getId().toString());
            }
        }
        return parentOrganizationIds;
    }

    /**
     * 递归生成机构树
     *
     * @param organizations 机构集合
     * @return List<Organization>
     */
    private List<Organization> getOrganizationTree(List<Organization> organizations) {
        List<Organization> organizationList = new ArrayList<>();
        for (Organization organization : getParentOrganizationTree(organizations)) {
            this.getChildrenOrganizationTree(organization, organizations);
            organizationList.add(organization);
        }
        return organizationList;
    }

    /**
     * 生成父级机构树
     *
     * @param organizations 机构集合
     * @return List<Organization>
     */
    private List<Organization> getParentOrganizationTree(List<Organization> organizations) {
        List<Organization> parentOrganizations = new ArrayList<>();
        for (Organization organization : organizations) {
            List<Organization> currentOrganizationParents = organizations.stream().filter(o -> o.getId().equals(organization.getParentId())).collect(Collectors.toList());
            if (currentOrganizationParents.size() <= 0) {
                parentOrganizations.add(organization);
            }
        }
        return parentOrganizations;
    }

    /**
     * 递归生成子机构树节点
     *
     * @param parentOrganization 上级机构
     * @param organizations      机构集合
     * @return Organization
     */
    private Organization getChildrenOrganizationTree(Organization parentOrganization, List<Organization> organizations) {
        List<Organization> childrenOrganizations = new ArrayList<>();
        for (Organization organization : organizations) {
            if (parentOrganization.getId().equals(organization.getParentId())) {
                childrenOrganizations.add(getChildrenOrganizationTree(organization, organizations));
            }
        }
        if (childrenOrganizations.size() > 0) {
            parentOrganization.setChildren(childrenOrganizations);
        }
        return parentOrganization;
    }

}
